
%define GetModuleHandleA [0x49f0b8]
%define GetProcAddress [0x49f130]
%define TerminateProcess [0x49f0ec]
%define MessageBoxA [0x49f140]

%define HeapStore 0x4a6238
;候補
;0x4a6238
;[0x4b5b4c]+0xa210
;[0x4b5b4c]+0xb300
;[0x4b5b4c]+0xbbc0

%macro GetEIP 0
push 8
push 0xc224048b ;mov eax,[esp]#ret 8
call esp
%endmacro
%macro RegisterError 1
dd Message%1-Message
%endmacro
%macro RiseError 1
push %1
call Error
jmp Return
%endmacro
%macro calloc 2
push %2
push %1
mov eax,0x492ded ;calloc(number,size)
call eax
add esp,4*2
%endmacro

%define varread_size Routine.varwrite-Routine.varread
%define varwrite_size Routine.fvarread-Routine.varwrite
%define fvarread_size Routine.fvarwrite-Routine.fvarread
%define fvarwrite_size Routine.playerupdate-Routine.fvarwrite
%define playerupdate_size Routine.foot-Routine.playerupdate

%define varread_base 0x47b7df
%define varwrite_base 0x407e81
%define fvarread_base 0x47b842
%define fvarwrite_base 0x407f86
%define playerupdate_base 0x442432

Main: ;VER(selector)
push ebp
mov ebp,esp
pushad
mov ecx,[ebp+0x8]
Switch:
inc ecx
dec ecx
jz Prepare_routine ;case 0 準備のみ
dec ecx
jz Change_routine ;case 1 適用のみ
dec ecx
jz Restore_routine ;case 2 修正のみ
dec ecx
jz Prepare_routine ;case 3 準備と適用
jmp Return ;default
;===================================Switch end========

Prepare_routine:
mov ebx,[HeapStore]
test ebx,ebx
jz .alloc_heap_base
cmp dword ptr [ebx+0x14],0
ja .do_change_routine
jmp .alloc_if1

.alloc_heap_base:
calloc 6,4
test eax,eax
jz RiseError4
.store_heapstore:
mov ebx,eax
mov dword ptr [HeapStore],ebx

.alloc_if1:
cmp dword ptr [ebx],0
jne .store_routine1
.alloc_heap1:
calloc varread_size,1
test eax,eax
jz RiseError1
mov dword ptr [ebx],eax
.store_routine1:
mov ecx,varread_size
mov edi,[ebx]
mov esi,varread_base
rep movsb

.alloc_if2:
cmp dword ptr [ebx+4],0
jne .store_routine2
.alloc_heap2:
calloc varwrite_size,1
test eax,eax
jz RiseError1
mov dword ptr [ebx+4],eax
.store_routine2:
mov ecx,varwrite_size
mov edi,[ebx+4]
mov esi,varwrite_base
rep movsb

.alloc_if3:
cmp dword ptr [ebx+8],0
jne .store_routine3
.alloc_heap3:
calloc fvarread_size,1
test eax,eax
jz RiseError1
mov dword ptr [ebx+8],eax
.store_routine3:
mov ecx,fvarread_size
mov edi,[ebx+8]
mov esi,fvarread_base
rep movsb

.alloc_if4:
cmp dword ptr [ebx+0xc],0
jne .store_routine4
.alloc_heap4:
calloc fvarwrite_size,1
test eax,eax
jz RiseError1
mov dword ptr [ebx+0xc],eax
.store_routine4:
mov ecx,fvarwrite_size
mov edi,[ebx+0xc]
mov esi,fvarwrite_base
rep movsb

.alloc_if5:
cmp dword ptr [ebx+0x10],0
jne .store_routine5
.alloc_heap5:
calloc playerupdate_size,1
test eax,eax
jz RiseError1
mov dword ptr [ebx+0x10],eax
.store_routine5:
mov ecx,playerupdate_size
mov edi,[ebx+0x10]
mov esi,playerupdate_base
rep movsb

.do_change_routine:
cmp dword ptr [ebp+8],3
je Change_routine
jmp Return
;===================================Prepare_routine end========

Change_routine:
mov ecx,0xc3
cmp byte ptr [varread_base+5],cl
je Return
cmp byte ptr [varwrite_base+5],cl
je Return
cmp byte ptr [fvarread_base+5],cl
je Return
cmp byte ptr [fvarwrite_base+5],cl
je Return

.change_protect:
GetEIP
add eax,VirtualProtect-$
push eax
push 0x49f604 ;KERNEL32
call GetModuleHandleA
push eax
call GetProcAddress
mov esi,eax

push 0
push esp
push 0x40 ;PAGE_EXECUTE_READWRITE
push 0x9e000
push 0x401000
call esi ;VirtualProtect
add esp,4
test eax,eax
je RiseError3

.change_routine:
GetEIP
add eax,RoutineModded.varread-$
mov ebx,varread_base
mov byte ptr [ebx],0x68 ;push ...
mov dword ptr [ebx+1],eax ;...imm32
mov dword ptr [ebx+5],0x906690c3 ;ret#nop#o16 nop
mov dword ptr [ebx+9],0xff801f0f ;nop dword ptr [eax-0x00...
or dword ptr [ebx+0xc],-1 ;...000001]

add eax,RoutineModded.varwrite-RoutineModded.varread
mov ebx,varwrite_base
mov byte ptr [ebx],0x68 ;push ...
mov dword ptr [ebx+1],eax ;...imm32
mov dword ptr [ebx+5],0x906690c3 ;ret#nop#o16 nop
mov dword ptr [ebx+9],0x00041f0f ;nop dword ptr [eax+eax]
mov dword ptr [ebx+0xd],0xff801f0f ;nop dword ptr [eax-0x00...
or dword ptr [ebx+0x10],-1 ;...000001]

add eax,RoutineModded.fvarread-RoutineModded.varwrite
mov ebx,fvarread_base
mov byte ptr [ebx],0x68 ;push ...
mov dword ptr [ebx+1],eax ;...imm32
mov dword ptr [ebx+5],0x906690c3 ;ret#nop#o16 nop
mov dword ptr [ebx+9],0xff801f0f ;nop dword ptr [eax-0x00...
or dword ptr [ebx+0xc],-1 ;...000001]

add eax,RoutineModded.fvarwrite-RoutineModded.fvarread
mov ebx,fvarwrite_base
mov byte ptr [ebx],0x68 ;push ...
mov dword ptr [ebx+1],eax ;...imm32
mov dword ptr [ebx+5],0x906690c3 ;ret#nop#o16 nop
mov dword ptr [ebx+9],0x00041f0f ;nop dword ptr [eax+eax]
mov dword ptr [ebx+0xd],0x00041f0f ;nop dword ptr [eax+eax]
mov dword ptr [ebx+0x11],0xff801f0f ;nop dword ptr [eax-0x00...
or dword ptr [ebx+0x14],-1 ;...000001]

GetEIP
add eax,Main-$
mov ebx,playerupdate_base
mov byte ptr [ebx],0xb9 ;mov ecx,...
mov dword ptr [ebx+1],eax ;...imm32
mov dword ptr [ebx+5],0xd1ff026a ;push 2#call ecx
mov dword ptr [ebx+9],0x001f0f90 ;nop#nop dword ptr [eax]

mov ebx,[HeapStore]
inc dword ptr [ebx+0x14]

.restore_protect:
push 0
push esp
push 0x20 ;PAGE_EXECUTE_READ
push 0x9e000
push 0x401000
call esi ;VirtualProtect
add esp,4
jmp Return
;===================================Change_routine end=========

Restore_routine:
mov ecx,0xc3
cmp byte ptr [varread_base+5],cl
je .change_protect
cmp byte ptr [varwrite_base+5],cl
je .change_protect
cmp byte ptr [fvarread_base+5],cl
je .change_protect
cmp byte ptr [fvarwrite_base+5],cl
jne Return

.change_protect:
GetEIP
add eax,VirtualProtect-$
push eax
push 0x49f604 ;KERNEL32
call GetModuleHandleA
push eax
call GetProcAddress
mov ebx,eax
push eax

push 0
push esp
push 0x40 ;PAGE_EXECUTE_READWRITE
push 0x9e000
push 0x401000
call ebx ;VirtualProtect
add esp,4
test eax,eax
je RiseError3

.restore_routine:
mov ebx,[HeapStore]
mov esi,[ebx]
mov edi,varread_base
mov ecx,varread_size
rep movsb

mov esi,[ebx+4]
mov edi,varwrite_base
mov ecx,varwrite_size
rep movsb

mov esi,[ebx+8]
mov edi,fvarread_base
mov ecx,fvarread_size
rep movsb

mov esi,[ebx+0xc]
mov edi,fvarwrite_base
mov ecx,fvarwrite_size
rep movsb

mov esi,[ebx+0x10]
mov edi,playerupdate_base
mov ecx,playerupdate_size
rep movsb

mov ebx,[HeapStore]
dec dword ptr [ebx+0x14]

.is_from_PlayerUpdate:
cmp dword ptr [ebp+4],playerupdate_base+9
jne .restore_protect
sub dword ptr [ebp+4],9

.restore_protect:
pop ebx
push 0
push esp
push 0x20 ;PAGE_EXECUTE_READ
push 0x9e000
push 0x401000
call ebx ;VirtualProtect
add esp,4
jmp Return
;===================================Restore_routine end========

RiseError0:
RiseError 0
RiseError1:
RiseError 1
RiseError2:
RiseError 2
RiseError3:
RiseError 3
RiseError4:
RiseError 4

Return:
popad
leave
ret 4

Error:
push ebp
mov ebp,esp
mov ecx,[ebp+0x8]
GetEIP
add eax,Message-$
mov ecx,[eax+ecx*4]
add eax,ecx
push 0x10 ;MB_ICONERROR
push 0
push eax
push 0
call MessageBoxA
push 0
push -1
call TerminateProcess
leave
ret 4


VirtualProtect:
db "VirtualProtect",0
Message:
RegisterError .generic
RegisterError .alloc_heap
RegisterError .get_vpaddr
RegisterError .vp
RegisterError .alloc_heapstore
.generic:
db "Unexpected error occurred.",0 ;0
.alloc_heap:
db "Cannot allocate heap for routine.",0 ;1
.get_vpaddr:
db "Cannot call VirtualProtect.",0 ;2
.vp:
db "Cannot change protection.",0 ;3
.alloc_heapstore:
db "Cannot allocate heap for heapstore.",0 ;4


Routine:
.varread:
test eax,eax
jl $+2+0x15
cmp eax,0x3b
jg $+2+0x10
mov edx,[esi+eax*4+0xe40]
.varwrite:
test ebx,ebx
jl $+2+0x1b
cmp ebx,0x3c
jg $+2+0x16
mov edx,[esp+0x4c]
mov dword ptr [edx+ebx*4+0xe40],edi
.fvarread:
test edx,edx
jl $+2+0x15
cmp edx,0x27
jg $+2+0x10
fld dword ptr [esi+edx*4+0xf30]
.fvarwrite:
test ebx,ebx
jl $+2+0x1f
cmp ebx,0x28
jg $+2+0x1a
fld dword ptr [esp+0x10]
mov eax,[esp+0x4c]
fstp dword ptr [eax+ebx*4+0xf30]
.playerupdate:
mov ecx,[0x4b5b4c]
pop edi
mov edx,[ecx+0xb3fc]
.foot:

RoutineModded:
align 0x10
.varread:
cmp eax,0d2543
jg .varread_g
cmp eax,-0d912
jl .varread_g
.varread_p:
mov edx,[esi+eax*4+0xe40]
jmp .varread_return
.varread_g:
mov edx,[eax]
.varread_return:
push 0x47b7ef
ret

align 0x10,nop
.varwrite:
cmp ebx,0d2543
jg .varwrite_g
cmp ebx,-0d912
jl .varwrite_g
.varwrite_p:
mov edx,[esp+0x4c]
mov dword ptr [edx+ebx*4+0xe40],edi
jmp .varwrite_return
.varwrite_g:
mov dword ptr [ebx],edi
.varwrite_return:
push 0x407e95
ret

align 0x10,nop
.fvarread:
cmp edx,0d2483
jg .fvarread_g
cmp edx,-0d972
jl .fvarread_g
.fvarread_p:
fld dword ptr [esi+edx*4+0xf30]
jmp .fvarread_return
.fvarread_g:
fld dword ptr [edx]
.fvarread_return:
push 0x47b852
ret

align 0x10,nop
.fvarwrite:
fld dword ptr [esp+0x10]
cmp ebx,0d2583
jg .fvarwrite_g
cmp ebx,-0d972
jl .fvarwrite_g
.fvarwrite_p:
mov dword ptr [esp+0x24],ebx
mov eax,[esp+0x4c]
fstp dword ptr [eax+ebx*4+0xf30]
jmp .fvarwrite_return
.fvarwrite_g:
mov ebx,[esp+0x24]
fstp dword ptr [ebx]
.fvarwrite_return:
push 0x407f9e
ret

